#ifndef SIMP_PIDDEVICE_H
#define SIMP_PIDDEVICE_H

#include "stdint.h"

#ifdef __cplusplus
extern "C"
{
#endif

	typedef struct
	{
		void (*cal)(void);
		void (*pv_set)(float pv);
		void (*sv_set)(float sv);
		void (*clr)(void);
		void (*dv_clr)(void);
		void (*weak)(float coef);
		void (*update)(uint16_t *tab, float min, float max);
	} simp_pid_api_type;

#define SIMPID_DM_PVD_NOR 0
#define SIMPID_DM_PVD_SEM 1

	typedef struct simp_pid_str
	{
		struct
		{
			uint8_t reset;	
			uint8_t dv_clr; 
		} cmd;

		struct
		{
			uint8_t dead_zone_mode; 
			uint8_t i_tab_en;		
			uint8_t d_mode;			
			uint8_t d_limit_en : 1;		   
			uint8_t ctrz_mode : 1;		   
			uint8_t po_dis_en : 1;		   
			uint8_t ext_d_coef_en : 1;	   
			uint8_t i_separate_en : 1;     
			uint8_t iv_suppression_en : 1; 
		} func;						
		struct						
		{							
			uint16_t kt_sv;			
			uint16_t kt_cycle;		
			uint16_t P, I, D;		
		} cfg;						
		struct						
		{							
			float sp_pfac;			
									
			struct
			{
				float err;			
				float coef;			
			} tab[5];				
			float suppression_rang; 
			int16_t iout_rst;		
			int16_t iout_min;		
			int16_t iout_max;		
		} icfg;						
		float dead_zone;			
		float d_limit;				
		float ctr_zone_entry;		
		float ctr_zone_quit;		
		float out_min;				
		float out_max;				
		float sv;					
		float pv;					
		struct						
		{							
			float i_separate;	    
			float d_coef_up;		
			float d_coef_dn;		
		} ext;						
		struct						
		{							
			float fac;				
			float offset;			
		} out_cfg;					
		struct                      
		{                           
			float kkp, kki, kkd;    
			float dkp, dki, dkd;    
			void (*func)(struct simp_pid_str *pid); 
		}fuzzy;                     
		
		int32_t out;				
		float out_adj;				

		struct
		{
			float out_coef;			 
			float out_coef_flt;		 
			float kp, ki, kd, dft;	 
			float pv_old[2];
			float sv_old;
			float err_old;
			float dv_diff; 
			float oks[3];
			uint16_t chk_cnt;
			uint16_t kt_cnt;		
			uint16_t Po, Io, Do, To; 
			uint8_t ctrz_st;			
			uint8_t ien_st;			
			uint8_t po_dis_st;
			int8_t dir; 
			int8_t st_cal_pulse; 
		} aux;
		float dv;
		float uk;
		float iken;
		const simp_pid_api_type *api; 
	} simp_pid_type;

	void simp_pid_clr(simp_pid_type *pid);													  
	void simp_pid_dv_clr(simp_pid_type *pid);												  
	void simp_pid_pv_set(simp_pid_type *pid, float pv);										  
	void simp_pid_sv_set(simp_pid_type *pid, float sv);										  
	void simp_pid_out_weaken(simp_pid_type *pid, float Coef);								  
	void simp_pid_update(simp_pid_type *pid, uint16_t *ParTab, float DutyMin, float DutyMax); 
	void simp_pid(simp_pid_type *pid);														  
	void simp_pid_fuzzy_7_model(struct simp_pid_str* pid);                                    

#define simp_pid_api_make(name, p_obj)                                        \
	static void name##_cal(void);                                             \
	static void name##_pv_set(float pv);                                      \
	static void name##_sv_set(float sv);                                      \
	static void name##_clr(void);                                             \
	static void name##_dv_clr(void);                                          \
	static void name##_weak(float coef);                                      \
	static void name##_update(uint16_t *tab, float min, float max);           \
                                                                              \
	static void name##_cal(void) { simp_pid(p_obj); }                         \
	static void name##_pv_set(float pv) { simp_pid_pv_set(p_obj, pv); }       \
	static void name##_sv_set(float sv) { simp_pid_sv_set(p_obj, sv); }       \
	static void name##_clr(void) { simp_pid_clr(p_obj); }                     \
	static void name##_dv_clr(void) { simp_pid_dv_clr(p_obj); }               \
	static void name##_weak(float coef) { simp_pid_out_weaken(p_obj, coef); } \
	static void name##_update(uint16_t *tab, float min, float max)            \
	{                                                                         \
		simp_pid_update(p_obj, tab, min, max);                                \
	}                                                                         \
                                                                              \
	const simp_pid_api_type name##_pid_api = {                                \
		name##_cal,                                                           \
		name##_pv_set,                                                        \
		name##_sv_set,                                                        \
		name##_clr,                                                           \
		name##_dv_clr,                                                        \
		name##_weak,                                                          \
		name##_update}

#define simp_pid_api_link(name, p_obj) p_obj->api = name##_pid_api
#define simp_pid_api_ref(name, p_obj) extern const simp_pid_api_type name##_pid_api;

#ifdef __cplusplus
}
#endif

#endif 
